package com.wlx.file.utils;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;


/**
 * 阿里云oss 存储服务
 * 示例说明
 * <p>
 * HelloOSS是OSS Java SDK的示例程序，您可以修改endpoint、accessKeyId、accessKeySecret、bucketName后直接运行。
 * 运行方法请参考README。
 * <p>
 * 本示例中的并不包括OSS Java SDK的所有功能，详细功能及使用方法，请参看“SDK手册 > Java-SDK”，
 * 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/preface.html?spm=5176.docoss/sdk/java-sdk/。
 * <p>
 * 调用OSS Java SDK的方法时，抛出异常表示有错误发生；没有抛出异常表示成功执行。
 * 当错误发生时，OSS Java SDK的方法会抛出异常，异常中包括错误码、错误信息，详细请参看“SDK手册 > Java-SDK > 异常处理”，
 * 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/exception.html?spm=5176.docoss/api-reference/error-response。
 * <p>
 * OSS控制台可以直观的看到您调用OSS Java SDK的结果，OSS控制台地址是：https://oss.console.aliyun.com/index#/。
 * OSS控制台使用方法请参看文档中心的“控制台用户指南”， 指南的来链接地址是：https://help.aliyun.com/document_detail/oss/getting-started/get-started.html?spm=5176.docoss/user_guide。
 * <p>
 * OSS的文档中心地址是：https://help.aliyun.com/document_detail/oss/user_guide/overview.html。
 * OSS Java SDK的文档地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/install.html?spm=5176.docoss/sdk/java-sdk。
 *
 * @author: huwei
 * @date: 2019/12/6 15:04
 * @version: 1.0.0
 */
public class AliyunOssStore {
    private static final Logger log = LoggerFactory.getLogger(AliyunOssStore.class);

    /**
     * 阿里云oss服务器地址
     */
    private String endpoint;
    /**
     * 阿里云key id
     */
    private String accessKeyId;
    /**
     * 阿里云访问Secret
     */
    private String accessKeySecret;
    private String bucketName;
    private String cdn;

    public AliyunOssStore() {
    }

    public AliyunOssStore(String endpoint, String accessKeyId, String accessKeySecret, String bucketName, String cdn) {
        Assert.notEmpty(new String[]{endpoint, accessKeyId, accessKeySecret, bucketName, cdn}, "oss参数不能为空");
        this.endpoint = endpoint;
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
        this.bucketName = bucketName;
        this.cdn = cdn;
    }

    /**
     * @return
     * @Title: getOSSClient
     * @Description: 获取OSS客户端
     * @return: OSSClient
     */
    public synchronized OSSClient getOSSClient() {
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        } catch (Exception e) {
            log.error("获取OSS客户端异常", e);
        }
        return ossClient;
    }

    /**
     * 线程等待时间
     *
     * @param seconds 等待时间（秒）
     */
    public void sleep(int seconds) {
        if (seconds <= 0) {
            return;
        }
        try {
            Thread.sleep(seconds * 1000);
        } catch (InterruptedException e) {

        }
    }

    public String uploadFileToOSS(File srcFile, String saveKey) {
        if (srcFile == null || !srcFile.exists() || srcFile.isDirectory()) {
            log.error("上传文件错误，为空或不是正文件");
            return null;
        }
        try {
            return uploadFileToOSS(new FileInputStream(srcFile), saveKey);
        } catch (FileNotFoundException e) {
            log.error("上传文件错误，文件不存在 ,file :" + srcFile.getAbsolutePath());
            return null;
        }
    }

    public String uploadFileToOSS(byte[] buf, String saveKey) {
        return uploadFileToOSS(new ByteArrayInputStream(buf), saveKey);
    }

    public String uploadFileToOSS(InputStream is, String saveKey) {
        if (saveKey.indexOf("/") == 0) {
            saveKey = saveKey.substring(1, saveKey.length());
        }
        // 获取客户端
        OSSClient ossClient = getOSSClient();
        try {
            if (StringUtils.isEmpty(bucketName)) {
                log.error("阿里云OSS配置错误，找不到Bucket配置！");
                return null;
            }
            if (ossClient.doesBucketExist(bucketName)) {
                log.error("您已经创建Bucket：" + bucketName + "。");
            } else {
                log.error("您的Bucket不存在，创建Bucket：" + bucketName + "。");
                ossClient.createBucket(bucketName);
            }
            // 上传文件
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, saveKey, is);
            ossClient.putObject(putObjectRequest);
            return saveKey;
        } catch (Exception e) {
            log.error("OSS上传文件出错,停止上传该文件!", e);
        } finally {
            ossClient.shutdown();
        }
        return saveKey;
    }

    /**
     * 验证OSS上是否存在名称为bucketName的Bucket
     *
     * @param oss
     * @param bucketName
     * @return
     */
    public boolean checkBucketExists(OSSClient oss, String bucketName) {
        List<Bucket> buckets = oss.listBuckets();
        for (Bucket bucket : buckets) {
            if (Objects.equals(bucket.getName(), bucketName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param out 文件输出流
     * @param key 文件地址
     * @Title: downOutputStream
     * @Description: 输出文件流，用于下载
     * @return: void
     */
    public void downOutputStream(OutputStream out, String key) {
        // 获取客户端
        OSSClient ossClient = getOSSClient();
        try {
            OSSObject ossObject = null;
            try {
                ossObject = ossClient.getObject(bucketName, key);
            } catch (Exception e) {
                log.error("文件不存在，key：" + key);
                return;
            }
            byte[] buffer = new byte[8192];

            InputStream objectData = ossObject.getObjectContent();
            int bytesRead = 0;
            while ((bytesRead = objectData.read(buffer, 0, 8192)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            objectData.close();
        } catch (Exception ase) {
            log.error("下载异常！", ase);
        } finally {
            try {
                ossClient.shutdown();
                out.flush();
                out.close();
            } catch (Exception e) {
            }
        }
    }

    /**
     * @param saveKey 文件地址（不包含桶名）
     * @Title: deleteFileFromOSS
     * @Description: 从OSS删除文件
     * @return: void
     */
    public void deleteFileFromOSS(String saveKey) {
        deleteFileFromOSS(Arrays.asList(saveKey));
    }

    public void deleteFileFromOSS(List<String> saveKeyList) {
        // 获取客户端
        OSSClient ossClient = getOSSClient();
        try {
            DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName);
            deleteObjectsRequest.setKeys(saveKeyList);
            ossClient.deleteObjects(deleteObjectsRequest);
        } catch (Exception e) {
            log.error("OSS删除文件异常", e);
        } finally {
            ossClient.shutdown();
        }
    }

    public ObjectListing searchByPage(String queryKey, String nextMarker, int size) {
        ObjectListing objectListing = null;
        OSSClient ossClient = this.getOSSClient();
        try {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
            listObjectsRequest.setBucketName(bucketName);
            listObjectsRequest.setPrefix(queryKey);
            listObjectsRequest.setDelimiter("/");
            listObjectsRequest.withMarker(nextMarker);
            listObjectsRequest.setMaxKeys(size);
            objectListing = ossClient.listObjects(listObjectsRequest);
        } catch (Exception e) {
            log.error("OSS获取文件列表失败", e);
        } finally {
            ossClient.shutdown();
        }
        return objectListing;

    }

    public boolean doesObjectExist(String queryKey) {
        OSSClient ossClient = this.getOSSClient();
        try {
            return ossClient.doesObjectExist(bucketName, queryKey);
        } catch (Exception e) {
            log.error("OSS操作失败", e);
        } finally {
            ossClient.shutdown();
        }
        return true;
    }


    public void copyFile(String originKey, String newKey) {
        OSSClient ossClient = getOSSClient();
        try {
            //重命名文件
            CopyObjectRequest copyObjectRequest = new CopyObjectRequest(
                    bucketName,
                    originKey,
                    bucketName,
                    newKey);
            CopyObjectResult objectResult = ossClient.copyObject(copyObjectRequest);
        } catch (Exception e) {
            log.error("OSS操作失败", e);
        } finally {
            ossClient.shutdown();
        }
    }

    public ObjectListing searchAll(String key) {
        OSSClient ossClient = getOSSClient();
        try {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
            listObjectsRequest.setBucketName(bucketName);
            listObjectsRequest.setPrefix(key);
            return ossClient.listObjects(listObjectsRequest);
        } catch (Exception e) {
            log.error("OSS操作失败", e);
        } finally {
            ossClient.shutdown();
        }
        return null;
    }

    public void download(String key, OutputStream out) {
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSClient ossClient = getOSSClient();
        try {
            OSSObject ossObject = ossClient.getObject(bucketName, key);
            InputStream in = ossObject.getObjectContent();
            try {
                byte buffer[] = new byte[1024];
                int len = 0;
                //循环将输入流中的内容读取到缓冲区当中
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
            } catch (Exception e) {

            } finally {
                try {
                    in.close();
                } catch (IOException e) {

                }
                in = null;
                try {
                    out.close();
                } catch (IOException e) {

                }
                out = null;
            }
        } catch (Exception e) {
            log.error("OSS操作失败", e);
        } finally {
            ossClient.shutdown();
        }


    }

    public void downloadLocal(String key, File file) {
        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
        OSSClient ossClient = getOSSClient();
        try {
            ossClient.getObject(new GetObjectRequest(bucketName, key), file);
        } catch (Exception e) {
            log.error("OSS操作失败", e);
        } finally {
            ossClient.shutdown();
        }
    }


    public String readFileContent(String key) throws IOException {
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSClient ossClient = this.getOSSClient();
        try {
            OSSObject ossObject = ossClient.getObject(bucketName, key);
            //读取文件内容
            InputStream inputStream = ossObject.getObjectContent();
            int size = Long.valueOf(ossObject.getObjectMetadata().getContentLength()).intValue();
            byte[] bytes = new byte[size];
            inputStream.read(bytes, 0, size);
            inputStream.close();
            return new String(bytes);
        } catch (Exception e) {
            log.error("OSS操作失败", e);
        } finally {
            ossClient.shutdown();
        }
        return "";

    }

    @Override
    public String toString() {
        return "AliyunOSSUtil [endpoint=" + endpoint + ", accessKeyId=" + accessKeyId + ", accessKeySecret="
                + accessKeySecret + ", bucketName=" + bucketName + ", cdn=" + cdn + "]";
    }


}
